use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;

use anyhow::{Context, Result};
use redis::{
    Client, 
    Connection, 
    ConnectionLike, 
    FromRedisValue, 
    ToRedisArgs, 
    Value,
    AsyncCommands,
    Commands,
};
use serde::{Deserialize, Serialize};
use tokio::sync::Mutex;
use tracing::{error, info, warn};

/// Redis客户端封装
#[derive(Clone)]
pub struct RedisClient {
    client: Arc<Mutex<Client>>,
    connection_info: RedisConnectionInfo,
}

/// Redis连接配置
#[derive(Clone, Debug)]
struct RedisConnectionInfo {
    host: String,
    port: u16,
    username: Option<String>,
    password: Option<String>,
    db: Option<i64>,
}

impl RedisClient {
    /// 创建新的Redis客户端
    pub fn new(
        host: &str, 
        port: u16, 
        username: Option<String>, 
        password: Option<String>, 
        db: Option<i64>
    ) -> Result<Self> {
        let connection_info = RedisConnectionInfo {
            host: host.to_string(),
            port,
            username,
            password,
            db,
        };

        let url = Self::build_connection_url(&connection_info)?;
        let client = Client::open(url)?;

        info!(
            "初始化Redis客户端: {}:{}",
            connection_info.host, connection_info.port
        );

        Ok(Self {
            client: Arc::new(Mutex::new(client)),
            connection_info,
        })
    }

    /// 构建Redis连接URL
    fn build_connection_url(info: &RedisConnectionInfo) -> Result<String> {
        let mut url = format!("redis://{}:{}", info.host, info.port);

        if let Some(username) = &info.username {
            url.push_str(&format!("/{}", username));
        }

        if let Some(password) = &info.password {
            url = format!("redis://{}:{}@{}", 
                info.username.clone().unwrap_or_default(), 
                password, 
                url.replace("redis://", "")
            );
        }

        if let Some(db) = info.db {
            url.push_str(&format!("/{}", db));
        }

        Ok(url)
    }

    /// 获取同步连接
    fn get_sync_connection(&self) -> Result<Connection> {
        let client = self.client.blocking_lock().clone();
        client.get_connection().context("获取Redis同步连接失败")
    }

    /// 设置键值对
    pub fn set<T: Serialize>(&self, key: &str, value: &T, expire: Option<Duration>) -> Result<()> {
        let serialized_value = serde_json::to_string(value)?;
        let mut conn = self.get_sync_connection()?;

        if let Some(duration) = expire {
            redis::cmd("SET")
                .arg(key)
                .arg(serialized_value)
                .arg("EX")
                .arg(duration.as_secs())
                .query(&mut conn)?;
        } else {
            conn.set(key, serialized_value)?;
        }

        Ok(())
    }

    /// 获取键值对
    pub fn get<T: for<'de> Deserialize<'de>>(&self, key: &str) -> Result<Option<T>> {
        let mut conn = self.get_sync_connection()?;
        let value: Option<String> = conn.get(key)?;

        match value {
            Some(v) => {
                let deserialized: T = serde_json::from_str(&v)?;
                Ok(Some(deserialized))
            }
            None => Ok(None),
        }
    }

    /// 删除键
    pub fn delete(&self, key: &str) -> Result<()> {
        let mut conn = self.get_sync_connection()?;
        conn.del(key)?;
        Ok(())
    }

    /// 设置过期时间
    pub fn expire(&self, key: &str, duration: Duration) -> Result<()> {
        let mut conn = self.get_sync_connection()?;
        conn.expire(key, duration.as_secs() as usize)?;
        Ok(())
    }

    /// 分布式锁
    pub fn lock(&self, key: &str, expire: Duration) -> Result<bool> {
        let mut conn = self.get_sync_connection()?;
        let result: Value = redis::cmd("SET")
            .arg(key)
            .arg("1")
            .arg("NX")
            .arg("EX")
            .arg(expire.as_secs())
            .query(&mut conn)?;

        Ok(result == Value::Ok)
    }

    /// 释放锁
    pub fn unlock(&self, key: &str) -> Result<()> {
        self.delete(key)
    }

    /// 发布消息
    pub fn publish<T: Serialize>(&self, channel: &str, message: &T) -> Result<()> {
        let serialized_message = serde_json::to_string(message)?;
        let mut conn = self.get_sync_connection()?;
        conn.publish(channel, serialized_message)?;
        Ok(())
    }

    /// 队列操作：推入元素
    pub fn push_to_queue<T: Serialize>(&self, queue_name: &str, item: &T) -> Result<()> {
        let serialized_item = serde_json::to_string(item)?;
        let mut conn = self.get_sync_connection()?;
        conn.rpush(queue_name, serialized_item)?;
        Ok(())
    }

    /// 队列操作：弹出元素
    pub fn pop_from_queue<T: for<'de> Deserialize<'de>>(&self, queue_name: &str) -> Result<Option<T>> {
        let mut conn = self.get_sync_connection()?;
        let value: Option<String> = conn.lpop(queue_name)?;

        match value {
            Some(v) => {
                let deserialized: T = serde_json::from_str(&v)?;
                Ok(Some(deserialized))
            }
            None => Ok(None),
        }
    }

    /// 哈希操作：设置哈希值
    pub fn hset<T: Serialize>(&self, key: &str, field: &str, value: &T) -> Result<()> {
        let serialized_value = serde_json::to_string(value)?;
        let mut conn = self.get_sync_connection()?;
        conn.hset(key, field, serialized_value)?;
        Ok(())
    }

    /// 哈希操作：获取哈希值
    pub fn hget<T: for<'de> Deserialize<'de>>(&self, key: &str, field: &str) -> Result<Option<T>> {
        let mut conn = self.get_sync_connection()?;
        let value: Option<String> = conn.hget(key, field)?;

        match value {
            Some(v) => {
                let deserialized: T = serde_json::from_str(&v)?;
                Ok(Some(deserialized))
            }
            None => Ok(None),
        }
    }

    /// 获取诊断信息
    pub fn diagnostics(&self) -> Result<HashMap<String, String>> {
        let mut conn = self.get_sync_connection()?;
        let mut info = HashMap::new();

        let server_info: redis::InfoDict = redis::cmd("INFO").query(&mut conn)?;
        
        info.insert("version".to_string(), server_info.get("redis_version").unwrap_or("Unknown").to_string());
        info.insert("uptime_in_seconds".to_string(), server_info.get("uptime_in_seconds").unwrap_or("Unknown").to_string());
        info.insert("connected_clients".to_string(), server_info.get("connected_clients").unwrap_or("Unknown").to_string());

        Ok(info)
    }
}

// 异步Redis客户端（可选）
#[derive(Clone)]
pub struct AsyncRedisClient {
    client: Arc<Client>,
    connection_info: RedisConnectionInfo,
}

impl AsyncRedisClient {
    pub async fn new(
        host: &str, 
        port: u16, 
        username: Option<String>, 
        password: Option<String>, 
        db: Option<i64>
    ) -> Result<Self> {
        let connection_info = RedisConnectionInfo {
            host: host.to_string(),
            port,
            username,
            password,
            db,
        };

        let url = RedisClient::build_connection_url(&connection_info)?;
        let client = Client::open(url)?;

        info!(
            "初始化异步Redis客户端: {}:{}",
            connection_info.host, connection_info.port
        );

        Ok(Self {
            client: Arc::new(client),
            connection_info,
        })
    }

    /// 异步设置键值对
    pub async fn set<T: Serialize>(&self, key: &str, value: &T, expire: Option<Duration>) -> Result<()> {
        let serialized_value = serde_json::to_string(value)?;
        let mut conn = self.client.get_async_connection().await?;

        if let Some(duration) = expire {
            conn.set_ex(key, serialized_value, duration.as_secs() as usize).await?;
        } else {
            conn.set(key, serialized_value).await?;
        }

        Ok(())
    }

    /// 异步获取键值对
    pub async fn get<T: for<'de> Deserialize<'de>>(&self, key: &str) -> Result<Option<T>> {
        let mut conn = self.client.get_async_connection().await?;
        let value: Option<String> = conn.get(key).await?;

        match value {
            Some(v) => {
                let deserialized: T = serde_json::from_str(&v)?;
                Ok(Some(deserialized))
            }
            None => Ok(None),
        }
    }
}

// 单元测试模块
#[cfg(test)]
mod tests {
    use super::*;
    use serde::{Deserialize, Serialize};
    use std::time::Duration;

    #[derive(Debug, Serialize, Deserialize, PartialEq)]
    struct TestStruct {
        name: String,
        age: u8,
    }

    #[test]
    fn test_redis_client() -> Result<()> {
        let client = RedisClient::new("localhost", 6379, None, None, None)?;

        // 测试设置和获取
        let test_data = TestStruct {
            name: "Alice".to_string(),
            age: 30,
        };

        client.set("test_key", &test_data, Some(Duration::from_secs(10)))?;
        let retrieved_data: Option<TestStruct> = client.get("test_key")?;
        
        assert_eq!(retrieved_data, Some(test_data));

        // 测试删除
        client.delete("test_key")?;
        let deleted_data: Option<TestStruct> = client.get("test_key")?;
        assert!(deleted_data.is_none());

        Ok(())
    }
}